open Base

(*** definition ***)

type (+'a, +'l) tree =
  | Arm of 'a * ('a, 'l) tree list
  | Leaf of 'l

type ('a, 'l) t = ('a, 'l) tree

module type SHOW_EQ = sig
  type t
  val to_string : t -> string
  val equal : t -> t -> bool
end

module Make_show_eq(A: SHOW_EQ)(L: SHOW_EQ)
  : SHOW_EQ with type t := (A.t, L.t) tree


(*** paths & zipper ***)

type path = int list

module Zipper : sig
  type (+'a, +'l) t
  val of_tree : ('a, 'l) tree -> ('a, 'l) t
  val to_tree : ('a, 'l) t -> ('a, 'l) tree
  module Error : sig
    type t = Bad_index | Not_arm | No_parent
    val to_string : t -> string
  end
  (* movement *)
  val up : ('a, 'l) t -> (('a, 'l) t, Error.t) Result.t
  val down : int -> ('a, 'l) t -> (('a, 'l) t, Error.t) Result.t
  val side : int -> ('a, 'l) t -> (('a, 'l) t, Error.t) Result.t
  val nav : ?prev:path -> targ:path -> ('a, 'l) t -> (('a, 'l) t, Error.t) Result.t
  (* accessor/modifier *)
  val get : ('a, 'l) t -> ('a, 'l) tree
  val set : ('a, 'l) tree -> ('a, 'l) t -> ('a, 'l) t
  (* "_exn" variants *)
  val up_exn : ('a, 'l) t -> ('a, 'l) t
  val down_exn : int -> ('a, 'l) t -> ('a, 'l) t
  val side_exn : int -> ('a, 'l) t -> ('a, 'l) t
  val nav_exn : ?prev:path -> targ:path -> ('a, 'l) t -> ('a, 'l) t
end
